package com.hevs.samplewebapp.client.screens;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

import com.google.gwt.cell.client.ButtonCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
import com.google.gwt.user.cellview.client.SimplePager.Resources;
import com.google.gwt.user.cellview.client.SimplePager.TextLocation;
import com.google.gwt.user.cellview.client.SimplePager;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.view.client.ListDataProvider;

import com.hevs.samplewebapp.client.Patient;
import com.hevs.samplewebapp.client.bean.CompositeWRefresh;
import com.hevs.samplewebapp.client.bean.User;
import com.hevs.samplewebapp.client.services.MedicalDataServiceImpl;

/**
 * Widget to grant or revoke a doctor
 * <p>It provides the patient the possibility to grant or revoke a doctor, so he can or cannot see the patient's medical data</p>
 * @author Thomas Rouvinez, Schnidrig Peter  
 * @date 32.03.2012
 */
public class GrantRevokeDoctorWidget extends CompositeWRefresh{

	// ------------------------------------------------------------
		// VARIABLES
		// ------------------------------------------------------------

	/**
	 * List of doctors granted by a patient
	 */
	private ListDataProvider<User> doctorsDataProvider;

	/**
	 * Celltable with the list of granted doctor in it
	 */
	private static CellTable<User> grantedDoctorsTable;
	
	/**
	 * Pager to go trought the list of Doctor when they are above 15
	 */
	private SimplePager grantedDoctorsPager;

	/**
	 * Column with the doctors firstname
	 */
	private TextColumn<User> firstNameColumn;
	
	/**
	 * Column with the doctors lastname
	 */
	private TextColumn<User> lastNameColumn;
	
	/**
	 * Column with the doctors email
	 */
	private TextColumn<User> emailColumn;

	/**
	 * Handler to sort the doctors by firstname
	 */
	private ListHandler<User> firstNameSortHandler;
	
	/**
	 * Handler to sort the doctors by lastname
	 */
	private ListHandler<User> lastNameSortHandler;
	
	/**
	 * Handler to sort the doctors by email
	 */
	private ListHandler<User> emailSortHandler;

	/**
	 * List of doctors from the Web service
	 */
	private List<User> doctorListRest = new ArrayList<User>();
	
	/**
	 * ClientBundle that provides pager images for this widget   
	 */
	private Resources resources=GWT.create(SimplePager.Resources.class); 

	/**
	 * Initialization of the web service to grant/revoke a doctor
	 */
	private static MedicalDataServiceImpl medicalDataService = new MedicalDataServiceImpl();

	/**
	 * Flextable that contains the grant form
	 */
	private FlexTable grantTable = new FlexTable();
	
	/**
	 * Instructions label
	 */
	private Label instruction = new Label("Enter e-mail of a doctor ");
	
	/**
	 * blank label
	 */
	private Label space = new Label("");
	
	/**
	 * Button to grant a doctor
	 */
	private Button grantDoctor = new Button("Grant");
	
	/**
	 * List of doctors
	 */
	private List<User> doctorList;
	
	/**
	 * Textbox to input the email of the dotor to grant
	 */
	private TextBox grantEmail = new TextBox();

	// ------------------------------------------------------------
	// CONSTRUCTOR
	// ------------------------------------------------------------
	/**
	 * Construcor of the Grant revoke Widget
	 */
	public GrantRevokeDoctorWidget(){

		// Construction layouts (panels).
		final VerticalPanel table = new VerticalPanel();
		final HorizontalPanel userInput = new HorizontalPanel();

		// ------------------------------------------------------------------------
		// Option to grant a new doctor using email address.
		// ------------------------------------------------------------------------

		space.setHeight("20px");
		instruction.setWidth("200px");
		grantEmail.setWidth("300px");
		grantDoctor.setWidth("100px");

		userInput.add(grantEmail);
		userInput.add(grantDoctor);

		grantDoctor.addClickHandler(new GrantDoctorHandler());

		// ------------------------------------------------------------------------
		// Cell table with doctors' names.
		// ------------------------------------------------------------------------

		buildTable();

		// ------------------------------------------------------------------------
		// Widget initialization.
		// ------------------------------------------------------------------------

		// Construct the 'grant' input table.
		grantTable.setWidth("100%");

		grantTable.setWidget(0, 0, space);
		grantTable.setWidget(1, 0, instruction);
		grantTable.setWidget(1, 1, userInput);
		grantTable.setWidget(2, 0, space);
		
		getDoctorsList();
		
		CellTableInnerListeners();
		// Add all main layouts to the widget.
		table.add(grantTable);
		table.add(grantedDoctorsTable);
		table.add(grantedDoctorsPager);
		table.setCellHorizontalAlignment(grantedDoctorsPager,VerticalPanel.ALIGN_CENTER);
		initWidget(table);
	}

	/**
	 * Method to build the cell table with the granted doctor in it
	 */
	private void buildTable() {
		grantedDoctorsTable = new CellTable<User>();

		// Get the list of doctors for the current user into the table content provider.
		doctorsDataProvider = new ListDataProvider<User>();
		
		// Create the pager for the table
		grantedDoctorsPager=new SimplePager(TextLocation.CENTER,resources,false,1000,true);
		grantedDoctorsPager.setDisplay(grantedDoctorsTable);
		grantedDoctorsPager.setPageSize(10);

		// Create the first name header of column.
		firstNameColumn = new TextColumn<User>() {
			@Override
			public String getValue(User doctor) {
				return doctor.getFirstName();
			}
		};

		// Create the last name header of column.
		lastNameColumn = new TextColumn<User>() {
			@Override
			public String getValue(User user) {
				return user.getLastName();
			}
		};

		// Create the email header of column.
		emailColumn = new TextColumn<User>() {
			@Override
			public String getValue(User doctor) {
				return doctor.getEmail();
			}
		};

		// Create the revoke button for every row.
		ButtonCell deleteButton= new ButtonCell();
		Column <User, String> delete= new Column <User, String>(deleteButton) {
			@Override
			public String getValue(User doctor) {
				return "Revoke";
			}
		};
		delete.setFieldUpdater(new FieldUpdater<User, String>() {
			@Override
			public void update(int index, User doctor, String value) {
				String email = doctor.getEmail();

				JSONObject user = new JSONObject();
				user.put("email", new JSONString(email));

				try {
					medicalDataService.sendDELETE(Patient.JSON_URL_REVOKE, user);
					getDoctorsList();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});

		// Make the relevant columns sortable (all in this case).
		firstNameColumn.setSortable(true);
		lastNameColumn.setSortable(true);
		emailColumn.setSortable(true);

		// Add the columns to the cell table.
		grantedDoctorsTable.addColumn(firstNameColumn, "First name");
		grantedDoctorsTable.addColumn(lastNameColumn, "Last name");
		grantedDoctorsTable.addColumn(emailColumn, "E-Mail");
		grantedDoctorsTable.addColumn(delete, "Action");

		// Set columns sizes.
		grantedDoctorsTable.setColumnWidth(firstNameColumn, 25.0, Unit.PCT);
		grantedDoctorsTable.setColumnWidth(lastNameColumn, 25.0, Unit.PCT);
		grantedDoctorsTable.setColumnWidth(emailColumn, 25.0, Unit.PCT);
		grantedDoctorsTable.setColumnWidth(delete, 10.0, Unit.PCT);

		// Set content of the table from the list of granted doctors for the current user.
		doctorsDataProvider.addDataDisplay(grantedDoctorsTable);
	}	

	@Override
	/**
	 * Method to refresh a component
	 */
	public void refreshComp(){
		
		doctorListRest = new ArrayList<User>();
		
		//Rest call to get a list of patients
		doctorListRest = medicalDataService.getDoctors();
		
		CellTableInnerListeners();
	}

	/**
	 * Listeners of the celltable to add doctor in it
	 */
	private void CellTableInnerListeners() {
		// Add the data to the data provider (filling the GUI table).
		doctorList = doctorsDataProvider.getList();
		doctorList.clear();

		for (User users : doctorListRest) {
			doctorList.add(users);
		}

		// ------------------------------------------------------------------------
		// Cell table's columns sorters.
		// ------------------------------------------------------------------------

		// First name sorter listener.
		firstNameSortHandler = new ListHandler<User>(doctorList);
		firstNameSortHandler.setComparator(firstNameColumn,
				new Comparator<User>() {
			public int compare(User o1, User o2) {
				if (o1 == o2) {
					return 0;
				}

				// Compare the name columns.
				if (o1 != null) {
					return (o2 != null) ? o1.getFirstName().compareTo(o2.getFirstName()) : 1;
				}
				return -1;
			}
		});

		// Last name sorter listener.
		lastNameSortHandler = new ListHandler<User>(doctorList);
		lastNameSortHandler.setComparator(lastNameColumn,
				new Comparator<User>() {
			public int compare(User o1, User o2) {
				if (o1 == o2) {
					return 0;
				}

				// Compare the name columns.
				if (o1 != null) {
					return (o2 != null) ? o1.getLastName().compareTo(o2.getLastName()) : 1;
				}
				return -1;
			}
		});

		// Last name sorter listener.
		emailSortHandler = new ListHandler<User>(doctorList);
		emailSortHandler.setComparator(emailColumn,
				new Comparator<User>() {
			public int compare(User o1, User o2) {
				if (o1 == o2) {
					return 0;
				}

				// Compare the name columns.
				if (o1 != null) {
					return (o2 != null) ? o1.getEmail().compareTo(o2.getEmail()) : 1;
				}
				return -1;
			}
		});


		grantedDoctorsTable.addColumnSortHandler(firstNameSortHandler);
		grantedDoctorsTable.addColumnSortHandler(lastNameSortHandler);
		grantedDoctorsTable.addColumnSortHandler(emailSortHandler);

		// We know that the data is sorted alphabetically by default.
		grantedDoctorsTable.getColumnSortList().push(firstNameColumn);
		grantedDoctorsTable.getColumnSortList().push(lastNameColumn);
		grantedDoctorsTable.getColumnSortList().push(emailColumn);
		
		
		grantedDoctorsTable.setRowCount(doctorListRest.size(), true);
	}

	/**
	 * Method to get the List of doctors from the server
	 */
	private void getDoctorsList() {
		medicalDataService.sendGetAllDoctor(this);
		doctorListRest = medicalDataService.getDoctors();
	}

	// ------------------------------------------------------------------------
	// Listeners.
	// ------------------------------------------------------------------------
	/**
	 * ClickHandler for granting a doctor button
	 */
	private class GrantDoctorHandler implements ClickHandler {
		@Override
		public void onClick(ClickEvent event) {
			String email = grantEmail.getText();
			JSONObject user = new JSONObject();
			user.put("email", new JSONString(email));

			try {
				medicalDataService.sendPOSTGrantDoctor(Patient.JSON_URL_GRANT, user);
				getDoctorsList();
			} catch (Exception e) {
				e.printStackTrace();
			}
			grantEmail.setText("");
		}
	}
}


